1 using System;
2 using
System.Collections.Generic;
3 using
UnityEngine;
4
5 namespace
UnityStandardAssets.Water
6 {
7     [ExecuteInEditMode]
// Make water live-update even when not in play mode
8     
public class Water : MonoBehaviour
9     {
10         
public enum WaterMode
11         {
12             Simple =
0,
13             Reflective =
1,
14             Refractive =
2,
15         };
16
17
18         
public WaterMode waterMode = WaterMode.Refractive;
19         
public bool disablePixelLights = true;
20         
public int textureSize = 256;
21         
public float clipPlaneOffset = 0.07f;
22         
public LayerMask reflectLayers = -1;
23         
public LayerMask refractLayers = -1;
24
25
26         
private Dictionary<Camera, Camera> m_ReflectionCameras = new Dictionary<Camera, Camera>(); // Camera -> Camera table
27         
private Dictionary<Camera, Camera> m_RefractionCameras = new Dictionary<Camera, Camera>(); // Camera -> Camera table
28         
private RenderTexture m_ReflectionTexture;
29         
private RenderTexture m_RefractionTexture;
30         
private WaterMode m_HardwareWaterSupport = WaterMode.Refractive;
31         
private int m_OldReflectionTextureSize;
32         
private int m_OldRefractionTextureSize;
33         
private static bool s_InsideWater;
34
35
36         
// This is called when it's known that the object will be rendered by some
37         
// camera. We render reflections / refractions and do other updates here.
38         
// Because the script executes in edit mode, reflections for the scene view
39         
// camera will just work!
40         
public void OnWillRenderObject()
41         {
42             
if (!enabled || !GetComponent<Renderer>() || !GetComponent<Renderer>().sharedMaterial ||
43                 !GetComponent<Renderer>().enabled)
44             {
45                 
return;
46             }
47
48             Camera cam = Camera.current;
49             
if (!cam)
50             {
51                 
return;
52             }
53
54             
// Safeguard from recursive water reflections.
55             
if (s_InsideWater)
56             {
57                 
return;
58             }
59             s_InsideWater =
true;
60
61             
// Actual water rendering mode depends on both the current setting AND
62             
// the hardware support. There's no point in rendering refraction textures
63             
// if they won't be visible in the end.
64             m_HardwareWaterSupport = FindHardwareWaterSupport();
65             WaterMode mode = GetWaterMode();
66
67             Camera reflectionCamera, refractionCamera;
68             CreateWaterObjects(cam,
out reflectionCamera, out refractionCamera);
69
70             
// find out the reflection plane: position and normal in world space
71             Vector3 pos = transform.position;
72             Vector3 normal = transform.up;
73
74             
// Optionally disable pixel lights for reflection/refraction
75             
int oldPixelLightCount = QualitySettings.pixelLightCount;
76             
if (disablePixelLights)
77             {
78                 QualitySettings.pixelLightCount =
0;
79             }
80
81             UpdateCameraModes(cam, reflectionCamera);
82             UpdateCameraModes(cam, refractionCamera);
83
84             
// Render reflection if needed
85             
if (mode >= WaterMode.Reflective)
86             {
87                 
// Reflect camera around reflection plane
88                 
float d = -Vector3.Dot(normal, pos) - clipPlaneOffset;
89                 Vector4 reflectionPlane =
new Vector4(normal.x, normal.y, normal.z, d);
90
91                 Matrix4x4 reflection = Matrix4x4.zero;
92                 CalculateReflectionMatrix(
ref reflection, reflectionPlane);
93                 Vector3 oldpos = cam.transform.position;
94                 Vector3 newpos = reflection.MultiplyPoint(oldpos);
95                 reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;
96
97                 
// Setup oblique projection matrix so that near plane is our reflection
98                 
// plane. This way we clip everything below/above it for free.
99                 Vector4 clipPlane = CameraSpacePlane(reflectionCamera, pos, normal,
1.0f);
100                 reflectionCamera.projectionMatrix = cam.CalculateObliqueMatrix(clipPlane);
101
102                 
// Set custom culling matrix from the current camera
103                 reflectionCamera.cullingMatrix = cam.projectionMatrix * cam.worldToCameraMatrix;
104
105                 reflectionCamera.cullingMask = ~(
1 << 4) & reflectLayers.value; // never render water layer
106                 reflectionCamera.targetTexture = m_ReflectionTexture;
107                 
bool oldCulling = GL.invertCulling;
108                 GL.invertCulling = !oldCulling;
109                 reflectionCamera.transform.position = newpos;
110                 Vector3 euler = cam.transform.eulerAngles;
111                 reflectionCamera.transform.eulerAngles =
new Vector3(-euler.x, euler.y, euler.z);
112                 reflectionCamera.Render();
113                 reflectionCamera.transform.position = oldpos;
114                 GL.invertCulling = oldCulling;
115                 GetComponent<Renderer>().sharedMaterial.SetTexture(
"_ReflectionTex", m_ReflectionTexture);
116             }
117
118             
// Render refraction
119             
if (mode >= WaterMode.Refractive)
120             {
121                 refractionCamera.worldToCameraMatrix = cam.worldToCameraMatrix;
122
123                 
// Setup oblique projection matrix so that near plane is our reflection
124                 
// plane. This way we clip everything below/above it for free.
125                 Vector4 clipPlane = CameraSpacePlane(refractionCamera, pos, normal, -
1.0f);
126                 refractionCamera.projectionMatrix = cam.CalculateObliqueMatrix(clipPlane);
127
128                 
// Set custom culling matrix from the current camera
129                 refractionCamera.cullingMatrix = cam.projectionMatrix * cam.worldToCameraMatrix;
130
131                 refractionCamera.cullingMask = ~(
1 << 4) & refractLayers.value; // never render water layer
132                 refractionCamera.targetTexture = m_RefractionTexture;
133                 refractionCamera.transform.position = cam.transform.position;
134                 refractionCamera.transform.rotation = cam.transform.rotation;
135                 refractionCamera.Render();
136                 GetComponent<Renderer>().sharedMaterial.SetTexture(
"_RefractionTex", m_RefractionTexture);
137             }
138
139             
// Restore pixel light count
140             
if (disablePixelLights)
141             {
142                 QualitySettings.pixelLightCount = oldPixelLightCount;
143             }
144
145             
// Setup shader keywords based on water mode
146             
switch (mode)
147             {
148                 
case WaterMode.Simple:
149                     Shader.EnableKeyword(
"WATER_SIMPLE");
150                     Shader.DisableKeyword(
"WATER_REFLECTIVE");
151                     Shader.DisableKeyword(
"WATER_REFRACTIVE");
152                     
break;
153                 
case WaterMode.Reflective:
154                     Shader.DisableKeyword(
"WATER_SIMPLE");
155                     Shader.EnableKeyword(
"WATER_REFLECTIVE");
156                     Shader.DisableKeyword(
"WATER_REFRACTIVE");
157                     
break;
158                 
case WaterMode.Refractive:
159                     Shader.DisableKeyword(
"WATER_SIMPLE");
160                     Shader.DisableKeyword(
"WATER_REFLECTIVE");
161                     Shader.EnableKeyword(
"WATER_REFRACTIVE");
162                     
break;
163             }
164
165             s_InsideWater =
false;
166         }
167
168
169         
// Cleanup all the objects we possibly have created
170         
void OnDisable()
171         {
172             
if (m_ReflectionTexture)
173             {
174                 DestroyImmediate(m_ReflectionTexture);
175                 m_ReflectionTexture =
null;
176             }
177             
if (m_RefractionTexture)
178             {
179                 DestroyImmediate(m_RefractionTexture);
180                 m_RefractionTexture =
null;
181             }
182             
foreach (var kvp in m_ReflectionCameras)
183             {
184                 DestroyImmediate((kvp.Value).gameObject);
185             }
186             m_ReflectionCameras.Clear();
187             
foreach (var kvp in m_RefractionCameras)
188             {
189                 DestroyImmediate((kvp.Value).gameObject);
190             }
191             m_RefractionCameras.Clear();
192         }
193
194
195         
// This just sets up some matrices in the material; for really
196         
// old cards to make water texture scroll.
197         
void Update()
198         {
199             
if (!GetComponent<Renderer>())
200             {
201                 
return;
202             }
203             Material mat = GetComponent<Renderer>().sharedMaterial;
204             
if (!mat)
205             {
206                 
return;
207             }
208
209             Vector4 waveSpeed = mat.GetVector(
"WaveSpeed");
210             
float waveScale = mat.GetFloat("_WaveScale");
211             Vector4 waveScale4 =
new Vector4(waveScale, waveScale, waveScale * 0.4f, waveScale * 0.45f);
212
213             
// Time since level load, and do intermediate calculations with doubles
214             
double t = Time.timeSinceLevelLoad / 20.0;
215             Vector4 offsetClamped =
new Vector4(
216                 (
float)Math.IEEERemainder(waveSpeed.x * waveScale4.x * t, 1.0),
217                 (
float)Math.IEEERemainder(waveSpeed.y * waveScale4.y * t, 1.0),
218                 (
float)Math.IEEERemainder(waveSpeed.z * waveScale4.z * t, 1.0),
219                 (
float)Math.IEEERemainder(waveSpeed.w * waveScale4.w * t, 1.0)
220                 );
221
222             mat.SetVector(
"_WaveOffset", offsetClamped);
223             mat.SetVector(
"_WaveScale4", waveScale4);
224         }
225
226         
void UpdateCameraModes(Camera src, Camera dest)
227         {
228             
if (dest == null)
229             {
230                 
return;
231             }
232             
// set water camera to clear the same way as current camera
233             dest.clearFlags = src.clearFlags;
234             dest.backgroundColor = src.backgroundColor;
235             
if (src.clearFlags == CameraClearFlags.Skybox)
236             {
237                 Skybox sky = src.GetComponent<Skybox>();
238                 Skybox mysky = dest.GetComponent<Skybox>();
239                 
if (!sky || !sky.material)
240                 {
241                     mysky.enabled =
false;
242                 }
243                 
else
244                 {
245                     mysky.enabled =
true;
246                     mysky.material = sky.material;
247                 }
248             }
249             
// update other values to match current camera.
250             
// even if we are supplying custom camera&projection matrices,
251             
// some of values are used elsewhere (e.g. skybox uses far plane)
252             dest.farClipPlane = src.farClipPlane;
253             dest.nearClipPlane = src.nearClipPlane;
254             dest.orthographic = src.orthographic;
255             dest.fieldOfView = src.fieldOfView;
256             dest.aspect = src.aspect;
257             dest.orthographicSize = src.orthographicSize;
258         }
259
260
261         
// On-demand create any objects we need for water
262         
void CreateWaterObjects(Camera currentCamera, out Camera reflectionCamera, out Camera refractionCamera)
263         {
264             WaterMode mode = GetWaterMode();
265
266             reflectionCamera =
null;
267             refractionCamera =
null;
268
269             
if (mode >= WaterMode.Reflective)
270             {
271                 
// Reflection render texture
272                 
if (!m_ReflectionTexture || m_OldReflectionTextureSize != textureSize)
273                 {
274                     
if (m_ReflectionTexture)
275                     {
276                         DestroyImmediate(m_ReflectionTexture);
277                     }
278                     m_ReflectionTexture =
new RenderTexture(textureSize, textureSize, 16);
279                     m_ReflectionTexture.name =
"__WaterReflection" + GetInstanceID();
280                     m_ReflectionTexture.isPowerOfTwo =
true;
281                     m_ReflectionTexture.hideFlags = HideFlags.DontSave;
282                     m_OldReflectionTextureSize = textureSize;
283                 }
284
285                 
// Camera for reflection
286                 m_ReflectionCameras.TryGetValue(currentCamera,
out reflectionCamera);
287                 
if (!reflectionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
288                 {
289                     GameObject go =
new GameObject("Water Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));
290                     reflectionCamera = go.GetComponent<Camera>();
291                     reflectionCamera.enabled =
false;
292                     reflectionCamera.transform.position = transform.position;
293                     reflectionCamera.transform.rotation = transform.rotation;
294                     reflectionCamera.gameObject.AddComponent<FlareLayer>();
295                     go.hideFlags = HideFlags.HideAndDontSave;
296                     m_ReflectionCameras[currentCamera] = reflectionCamera;
297                 }
298             }
299
300             
if (mode >= WaterMode.Refractive)
301             {
302                 
// Refraction render texture
303                 
if (!m_RefractionTexture || m_OldRefractionTextureSize != textureSize)
304                 {
305                     
if (m_RefractionTexture)
306                     {
307                         DestroyImmediate(m_RefractionTexture);
308                     }
309                     m_RefractionTexture =
new RenderTexture(textureSize, textureSize, 16);
310                     m_RefractionTexture.name =
"__WaterRefraction" + GetInstanceID();
311                     m_RefractionTexture.isPowerOfTwo =
true;
312                     m_RefractionTexture.hideFlags = HideFlags.DontSave;
313                     m_OldRefractionTextureSize = textureSize;
314                 }
315
316                 
// Camera for refraction
317                 m_RefractionCameras.TryGetValue(currentCamera,
out refractionCamera);
318                 
if (!refractionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
319                 {
320                     GameObject go =
321                         
new GameObject("Water Refr Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(),
322                             
typeof(Camera), typeof(Skybox));
323                     refractionCamera = go.GetComponent<Camera>();
324                     refractionCamera.enabled =
false;
325                     refractionCamera.transform.position = transform.position;
326                     refractionCamera.transform.rotation = transform.rotation;
327                     refractionCamera.gameObject.AddComponent<FlareLayer>();
328                     go.hideFlags = HideFlags.HideAndDontSave;
329                     m_RefractionCameras[currentCamera] = refractionCamera;
330                 }
331             }
332         }
333
334         WaterMode GetWaterMode()
335         {
336             
if (m_HardwareWaterSupport < waterMode)
337             {
338                 
return m_HardwareWaterSupport;
339             }
340             
return waterMode;
341         }
342
343         WaterMode FindHardwareWaterSupport()
344         {
345             
if (!GetComponent<Renderer>())
346             {
347                 
return WaterMode.Simple;
348             }
349
350             Material mat = GetComponent<Renderer>().sharedMaterial;
351             
if (!mat)
352             {
353                 
return WaterMode.Simple;
354             }
355
356             
string mode = mat.GetTag("WATERMODE", false);
357             
if (mode == "Refractive")
358             {
359                 
return WaterMode.Refractive;
360             }
361             
if (mode == "Reflective")
362             {
363                 
return WaterMode.Reflective;
364             }
365
366             
return WaterMode.Simple;
367         }
368
369         
// Given position/normal of the plane, calculates plane in camera space.
370         Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal,
float sideSign)
371         {
372             Vector3 offsetPos = pos + normal * clipPlaneOffset;
373             Matrix4x4 m = cam.worldToCameraMatrix;
374             Vector3 cpos = m.MultiplyPoint(offsetPos);
375             Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
376             
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
377         }
378
379         
// Calculates reflection matrix around the given plane
380         
static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane)
381         {
382             reflectionMat.m00 = (
1F - 2F * plane[0] * plane[0]);
383             reflectionMat.m01 = (-
2F * plane[0] * plane[1]);
384             reflectionMat.m02 = (-
2F * plane[0] * plane[2]);
385             reflectionMat.m03 = (-
2F * plane[3] * plane[0]);
386
387             reflectionMat.m10 = (-
2F * plane[1] * plane[0]);
388             reflectionMat.m11 = (
1F - 2F * plane[1] * plane[1]);
389             reflectionMat.m12 = (-
2F * plane[1] * plane[2]);
390             reflectionMat.m13 = (-
2F * plane[3] * plane[1]);
391
392             reflectionMat.m20 = (-
2F * plane[2] * plane[0]);
393             reflectionMat.m21 = (-
2F * plane[2] * plane[1]);
394             reflectionMat.m22 = (
1F - 2F * plane[2] * plane[2]);
395             reflectionMat.m23 = (-
2F * plane[3] * plane[2]);
396
397             reflectionMat.m30 =
0F;
398             reflectionMat.m31 =
0F;
399             reflectionMat.m32 =
0F;
400             reflectionMat.m33 =
1F;
401         }
402     }
403 }


Gõ tìm kiếm nhanh...